package com.kzj.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.kzj.dao.StudentDao;
import com.kzj.dao.TeacherDao;
import com.kzj.domain.Administrator;
import com.kzj.dao.AdministratorDao;
import com.kzj.domain.Student;
import com.kzj.domain.Teacher;
import com.kzj.domain.dto.ChangePasswordDTO;
import com.kzj.domain.dto.UserLoginDTO;
import com.kzj.domain.vo.ForbiddenVO;
import com.kzj.domain.vo.UserLoginVO;
import com.kzj.global.constant.GlobalConstant;
import com.kzj.global.exception.MyException;
import com.kzj.global.params.GlobalParams;
import com.kzj.global.re.Result;
import com.kzj.global.schedule.MySchedule;
import com.kzj.global.threadLocal.UserThreadLocal;
import com.kzj.global.utils.EncodeUtil;
import com.kzj.global.utils.GlobalUtil;
import com.kzj.global.utils.IdGeneratorUtil;
import com.kzj.global.utils.MatchesUtil;
import com.kzj.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kzj
 * @since 2023-12-01
 */
@Service
public class AdministratorServiceImpl extends ServiceImpl<AdministratorDao, Administrator> implements AdministratorService {
    @Autowired
    AdministratorDao administratorDao;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    TeacherService teacherService;
    @Autowired
    StudentService studentService;
    @Autowired
    AcademyService academyService;
    @Autowired
    MajorService majorService;
    @Autowired
    StudentClassService studentClassService;
    @Autowired
    EletiveCourseService eletiveCourseService;
    @Autowired
    GlobalParams globalParams;
    @Autowired
    MySchedule mySchedule;
    @Override
    public Result login(UserLoginDTO userLoginDTO) {

        LambdaQueryWrapper<Administrator> lqw=new LambdaQueryWrapper<>();
        lqw.eq(Administrator::getId,userLoginDTO.getId())
                .eq(Administrator::getPassword,userLoginDTO.getPassword());
        Administrator administrator = administratorDao.selectOne(lqw);
        if(administrator==null)
            return Result.error(GlobalConstant.ID_OR_PASSWORD_ERROR);
        administrator.setPassword(null);
        String key= EncodeUtil.encode(administrator.getId(),GlobalConstant.ADMINISTRATOR_INFO_PREFIX);

        UserLoginVO userLoginVO = new UserLoginVO();
        userLoginVO.setObj(administrator);
        userLoginVO.setType(GlobalConstant.ADMINISTRATOR_TYPE);
        userLoginVO.setToken(key);
        stringRedisTemplate.opsForValue().set(key, JSONObject.toJSONString(userLoginVO),GlobalConstant.LOGIN_INFO_TTL, TimeUnit.MINUTES);
        return Result.success(userLoginVO);
    }

    @Override
    public Result update(Administrator administrator) {
        MatchesUtil.idMatches(administrator.getId());
        MatchesUtil.objMatches(administrator);
        administrator.setPassword(null);
        administratorDao.updateById(administrator);
        String key=EncodeUtil.encode(administrator.getId(),GlobalConstant.ADMINISTRATOR_INFO_PREFIX);
        stringRedisTemplate.delete(key);
        return Result.success();
    }

    @Override
    public Result changePassword(ChangePasswordDTO changePasswordDTO) {
        MatchesUtil.passwordMatchers(changePasswordDTO.getNewPassword());
        MatchesUtil.passwordMatchers(changePasswordDTO.getOldPassword());
        Administrator user = UserThreadLocal.getUser(Administrator.class);
        String password = this.query().le("id", user.getId()).one().getPassword();
        if(!password.equals(EncodeUtil.encode(changePasswordDTO.getOldPassword())))
        {
            throw new MyException(GlobalConstant.PASSWORD_ERROR);
        }
        String encodeNewPassword=EncodeUtil.encode(changePasswordDTO.getNewPassword());
        this.update().eq("id",user.getId()).set("password",encodeNewPassword).update();
        return Result.success();
    }

    @Override
    public Result addAdministrator(Administrator administrator) {
        MatchesUtil.objMatches(administrator);
        String id = IdGeneratorUtil.generatorId(Administrator.class);
        administrator.setId(id);
        if(administrator.getPassword()==null)
        {
            String idNumber = administrator.getIdNumber();
            String password=idNumber.substring(idNumber.length()-GlobalConstant.PASSWORD_DEFAULT_LEN);
            administrator.setPassword(EncodeUtil.encode(password));
        }
        else administrator.setPassword(EncodeUtil.encode(administrator.getPassword()));
        this.save(administrator);
        return Result.success();
    }

    @Override
    public Result getAllAcademy() {
        return academyService.getAllAcademy();
    }

    @Override
    public Result getMajorByAcademyId(String academyId) {
        return majorService.getMajorByAcademyById(academyId);
    }

    @Override
    public Result getClassByMajorIdAndPeriod(String majorId,Integer period) {
        return studentClassService.getByMajorIdAndPeriod(majorId,period);
    }

    @Override
    public Result getStudentByStudentClassId(String studentClassId) {
        return studentService.getStudentByStudentClassId(studentClassId);
    }

    @Override
    public Result getStudentByMajorId(String majorId) {
        return studentService.getStudentByMajorId(majorId);
    }

    @Override
    public Result getStudentById(String studentId) {
        return studentService.getStudentById(studentId);
    }

    @Override
    public Result addStudent(Student student) {
        return studentService.addStudent(student);
    }

    @Override
    public Result addTeacher(Teacher teacher) {
        return teacherService.addTeacher(teacher);
    }

    @Override
    public Result getStudentByAcademyId(String academyId) {
        return studentService.getStudentByAcademyId(academyId);
    }

    @Override
    public Result getStudentSchedule(String studentId, Integer term) {
        return eletiveCourseService.getTotalSchedule(studentId,term);
    }

    @Override
    public Result getTeacherById(String teacherId) {
        return teacherService.getTeacherById(teacherId);
    }

    @Override
    public Result getTeacherSchedule(String teacherId, String curriculumTime) {
        return eletiveCourseService.getArrangeCourseList(teacherId,curriculumTime);
    }

    @Override
    public Result getStudentCurrentTermSchedule(String studentId) {
        Student student = studentService.getById(studentId);
        return eletiveCourseService.getTotalSchedule(studentId, GlobalUtil.getStudentTermByDateOfEnrollment(student.getDateOfEnrollment()));
    }

    @Override
    public Result getStudentNextTermSchedule(String studentId) {
        Student student = studentService.getById(studentId);
        return eletiveCourseService.getTotalSchedule(studentId, GlobalUtil.getStudentTermByDateOfEnrollment(student.getDateOfEnrollment())+1);
    }

    @Override
    public Result getTeacherCurrentTermSchedule(String teacherId) {
        return eletiveCourseService.getArrangeCourseList(teacherId,GlobalUtil.getCurrentTerm());
    }

    @Override
    public Result getTeacherNextTermSchedule(String teacherId) {
        return eletiveCourseService.getArrangeCourseList(teacherId,GlobalUtil.getTagTerm(1));
    }

    @Override
    public Result forbiddenStudent(ForbiddenVO forbiddenVO) {
        if(!(forbiddenVO.getStatus().equals(GlobalConstant.STATUS_UNUSABLE)||forbiddenVO.getStatus().equals(GlobalConstant.STATUS_USABLE)))
        {
             throw new MyException(GlobalConstant.STATUS_ERROR);
        }
        Student student = new Student();
        student.setId(forbiddenVO.getId());
        student.setStatus(forbiddenVO.getStatus());
        studentService.update(student);
        if(forbiddenVO.getStatus().equals(GlobalConstant.STATUS_UNUSABLE))
        {
            String key= EncodeUtil.encode(forbiddenVO.getId(),GlobalConstant.STUDENT_INFO_PREFIX);
            stringRedisTemplate.delete(key);
        }
        return Result.success();
    }
    @Override
    public Result forbiddenTeacher(ForbiddenVO forbiddenVO) {
        if(!(forbiddenVO.getStatus().equals(GlobalConstant.STATUS_UNUSABLE)||forbiddenVO.getStatus().equals(GlobalConstant.STATUS_USABLE)))        {
            throw new MyException(GlobalConstant.STATUS_ERROR);
        }
        Teacher teacher = new Teacher();
        teacher.setId(forbiddenVO.getId());
        teacher.setStatus(forbiddenVO.getStatus());
        teacherService.update(teacher);
        if(forbiddenVO.getStatus().equals(GlobalConstant.STATUS_UNUSABLE))
        {
            String key= EncodeUtil.encode(forbiddenVO.getId(),GlobalConstant.TEACHER_INFO_PREFIX);
            stringRedisTemplate.delete(key);
        }
        return Result.success();
    }

    @Override
    public Result stopRobClasses() {
        LocalDateTime now = LocalDateTime.now().plusSeconds(GlobalConstant.TASK_DELAY);
        return stopRobClasses(now);
    }
    @Override
    public Result stopRobClasses(LocalDateTime dateTime) {

        if(globalParams.getRobClassesPreHeatDate().isAfter(dateTime))
            throw new MyException(GlobalConstant.TIME_UNUSUAL);
        String key=GlobalConstant.STOP_ROB_CLASSES_KEY;
        DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern(GlobalConstant.DATE_TIME_FORMATTER);
        stringRedisTemplate.opsForValue().set(key,dateTime.format(dateTimeFormatter));
        globalParams.setStopRobClassesDate(dateTime);
        mySchedule.stopRobClasses();
        return Result.success();
    }
//    @Autowired
//    GlobalUtil globalUtil;
    @Override
    public Result startNextTermRobClasses() {
        LocalDateTime now = LocalDateTime.now().plusSeconds(GlobalConstant.TASK_DELAY);
        return startNextTermRobClasses(now);
    }

    @Override
    public Result startNextTermRobClasses(LocalDateTime dateTime) {
        if(dateTime.isBefore(LocalDateTime.now()))
        {
            throw new MyException(GlobalConstant.TIME_UNUSUAL);
        }
        String key=GlobalConstant.ROB_CLASSES_PREHEAT_KEY;
        DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern(GlobalConstant.DATE_TIME_FORMATTER);
        stringRedisTemplate.opsForValue().set(key,dateTime.format(dateTimeFormatter));
        globalParams.setRobClassesPreHeatDate(dateTime);
        mySchedule.robClassesPreheat();
        LocalDateTime stop=dateTime.plusDays(GlobalConstant.ROB_CLASSES_TIME);
        stopRobClasses(stop);
        return Result.success();
    }

    @Override
    public Result arrangeExamination() {

        LocalDateTime now = LocalDateTime.now().plusSeconds(GlobalConstant.TASK_DELAY);
        return arrangeExamination(now);
    }

    @Override
    public Result arrangeExamination(LocalDateTime dateTime) {
        stopRobClasses(dateTime);
        String key=GlobalConstant.ARRANGE_EXAMINATION_KEY;
        DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern(GlobalConstant.DATE_TIME_FORMATTER);
        stringRedisTemplate.opsForValue().set(key,dateTime.format(dateTimeFormatter));
        globalParams.setArrangeExaminationDate(dateTime);
        mySchedule.arrangeExaminationScheduled();
        return Result.success();
    }

    @Override
    public Result getTeacherByAcademyId(String academyId) {
        return teacherService.getAllTeacherByAcademyId(academyId);
    }

    @Override
    public Result getAllTeacher() {
        return Result.success(teacherService.list());
    }

    @Override
    public Result getCurrentTermScheduleList(String teacherId) {
        return eletiveCourseService.getTeacherCurrentTermScheduleByTeacherId(teacherId);
    }

    @Override
    public Result getNextTermScheduleList(String teacherId) {
        return eletiveCourseService.getTeacherNextTermScheduleByTeacherId(teacherId);
    }

    @Override
    public Result updateStudentInfo(Student student) {
        return studentService.updateStudent(student);
    }

    @Override
    public Result updateTeacherInfo(Teacher teacher) {
        return teacherService.updateTeacher(teacher);
    }



}
